﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ConsoleDBase
{
    partial class Menu
    {
        //TableOperations: option 0 - print active table
        private void PrintTable()
        {
            Details();

            int oldwidth = Console.WindowWidth;
            activedbase.PrintActiveTable(5, 10);

            List<string> options = new List<string>();
            options.Add("Vissza");

            SelectOption(options, false, 5, 10 + activedbase.activetable.NumOfRecords + 6);

            if (Console.WindowWidth != oldwidth)
                Console.SetWindowSize(oldwidth, Console.WindowHeight);
        }

        //TableOperations: option 1 - add new field to active table
        private void AddNewField()
        {
            Details();

            string name, type;
            bool isnullable = true;

            //field properties
            name = StringInput("Az új oszlop neve:", 10, 9);

            if (!LegalIdentifier(name))
            {
                ReportError(10, 12, "Helytelen azonosító");
                return;
            }

            for (int i = 0; i < activedbase.activetable.TableFields.Count; ++i)
            {
                if (activedbase.activetable.TableFields[i].Name == name)
                {
                    ReportError(10, 12, "Ilyen nevű oszlop már szerepel a táblában.");
                    return;
                }
            }

            Console.SetCursorPosition(10, 13);
            Console.WriteLine("Típusa:");

            List<string> types = new List<string>(new string[] { "Integer", "Real", "Boolean", "String" });
            type = types[SelectOption(types, false, 10, 15)];

            if (activedbase.activetable.NumOfRecords == 0)
            {
                Console.SetCursorPosition(10, 20);
                Console.Write("Hagyható-e üresen?");

                List<string> truefalse = new List<string>(new string[] { "Igen", "Nem" });
                isnullable = SelectOption(truefalse, false, 10, 22) == 0;
            }

            activedbase.activetable.UploadField(name, type, isnullable);
        }

        //TableOperations: option 2 - delete field from active table
        private void DeleteField()
        {
            Details();

            List<string> fields = new List<string>();
            foreach(Field f in activedbase.activetable.TableFields)
            {
                fields.Add(f.Name);
            }

            Console.SetCursorPosition(10, 9);
            Console.WriteLine("A törlendő oszlop:");

            string delete = fields[SelectOption(fields, false, 10, 11)];
            activedbase.activetable.DeleteField(delete);
        }

        //TableOperations: option 3 - add new records to active table
        private void AddRecord()
        {
            Details();

            string[] datas = new string[activedbase.activetable.TableFields.Count];
            List<Data> newrec = new List<Data>();

            Console.SetCursorPosition(10, 9);
            Console.Write("Add meg a rekord adatait!");
            Console.CursorVisible = true;

            for (int i = 0; i < activedbase.activetable.TableFields.Count; ++i)
            {
                Console.SetCursorPosition(10, 11 + i);
                string fieldtype = activedbase.activetable.TableFields[i].Type;

                Console.Write(activedbase.activetable.TableFields[i].Name + " (" + fieldtype + ", " + activedbase.activetable.TableFields[i].IsNullable + "): ");
                
                datas[i] = null;
                datas[i] = Console.ReadLine();
                if (datas[i] == "") datas[i] = null;

                Data newdat = null;

                //cheking type correction
                switch (fieldtype)
                {
                    case "Integer":
                        {
                            int value = 0;
                            try
                            {
                                if (!activedbase.activetable.TableFields[i].IsNullable && datas[i] == null) throw new Exception("A mező nem hagyható üresen.");
                                if (datas[i] != null) value = Int32.Parse(datas[i]);
                                if (activedbase.activetable.TableFields[i].IsNullable && datas[i] == null)
                                {
                                    newdat = new Integer(0, true);
                                }
                                else
                                {
                                    newdat = new Integer(value);
                                }
                            }
                            catch (System.Exception ex) { ReportError(10, 13 + i, "Hiba a bevitt adatokban!", ex.Message); return; }
                        } break;
                    case "Real": 
                        {
                            double value = 0;
                            try 
                            {
                                if (!activedbase.activetable.TableFields[i].IsNullable && datas[i] == null) throw new Exception("A mező nem hagyható üresen.");
                                if (datas[i] != null) value = Double.Parse(datas[i]);
                                if (activedbase.activetable.TableFields[i].IsNullable && datas[i] == null)
                                {
                                    newdat = new Real(0, true);
                                }
                                else
                                {
                                    newdat = new Real(value);
                                }
                            }
                            catch (System.Exception ex) { ReportError(10, 13 + i, "Hiba a bevitt adatokban!", ex.Message); return; }
                        } break;
                    case "Boolean":
                        {
                            bool value = false;
                            try 
                            {
                                if (!activedbase.activetable.TableFields[i].IsNullable && datas[i] == null) throw new Exception("A mező nem hagyható üresen.");
                                if (datas[i] != null) value = bool.Parse(datas[i]);
                                if (activedbase.activetable.TableFields[i].IsNullable && datas[i] == null)
                                {
                                    newdat = new Boolean(false, true);
                                }
                                else
                                {
                                    newdat = new Boolean(value);
                                }
                            }
                            catch (System.Exception ex) { ReportError(10, 13 + i, "Hiba a bevitt adatokban!", ex.Message); return; }
                        } break;
                    case "String":
                        {
                            try
                            {
                                if (!activedbase.activetable.TableFields[i].IsNullable && datas[i] == null) throw new Exception("A mező nem hagyható üresen.");
                                if (activedbase.activetable.TableFields[i].IsNullable && datas[i] == null)
                                {
                                    newdat = new String("", true);
                                }
                                else
                                {
                                    newdat = new String(datas[i]);
                                }
                            }
                            catch (System.Exception ex) { ReportError(10, 13 + i, "Hiba a bevitt adatokban!", ex.Message); return; }
                        } break;
                }

                newrec.Add(newdat);
            }

            //activedbase.activetable.UploadRecord(datas);
            activedbase.activetable.UploadRecord(newrec);
        }

        private void ReportError(int cursorleft, int cursortop, string msg, string exmsg = null)
        {
            Console.SetCursorPosition(cursorleft, cursortop);
            Console.ForegroundColor = ConsoleColor.Red;

            Console.Write(msg);
            if (exmsg != null)
            {
                Console.SetCursorPosition(cursorleft, cursortop + 1);
                Console.Write(exmsg);
            }

            Console.ForegroundColor = ConsoleColor.DarkGray;
            Console.ReadKey();
        }

        //TableOperations: option 4 - filter in active table
        private void Filtering()
        {
            Details();

            Console.SetCursorPosition(10, 9);
            Console.WriteLine("Válaszd ki a mezőt, amely alapján a szűrés elvégzendő:");

            List<string> fields = new List<string>();
            foreach (Field f in activedbase.activetable.TableFields)
            {
                fields.Add(f.Name);
            }

            int filterfield = SelectOption(fields, false, 10, 12); //field of filtering
            string filterfieldtype = activedbase.activetable.TableFields[filterfield].Type;

            List<int> result = new List<int>();

            switch (filterfieldtype)
            {
                case "Integer": result = NumberFiltering(filterfield); break;
                case "Real": result = NumberFiltering(filterfield); break;
                case "Boolean": result = NonNumberFiltering(filterfield); break;
                case "String": result = NonNumberFiltering(filterfield); break;
            }

            //managing the result
            ManageResult(result);
        }

        void ManageResult(List<int> result)
        {
            List<string> options = new List<string>(new string[] { "Listázás", "Rekordok törlése a táblából", "Vissza" });
            int s;

            do
            {
                Details();

                Console.SetCursorPosition(10, 9);
                Console.Write("A feltételnek eleget tevő rekordok száma: ");
                Console.Write(result.Count);

                s = SelectOption(options, true, 10, 11);
                int del = 1;

                switch (s)
                {
                    case 0: PrintResult(result); break;
                    case 1: del = DeleteResult(result); break;
                    case 2: return;
                }

                if (del == 0) return;
            } while (true);
        }

        void PrintResult(List<int> result)
        {
            Details();

            int oldwidth = Console.WindowWidth;
            activedbase.activetable.PrintTable(10, 9, result);

            List<string> options = new List<string>();
            options.Add("Vissza");

            SelectOption(options, false, 5, 10 + activedbase.activetable.Records.Count + 6);

            if (Console.WindowWidth != oldwidth)
                Console.SetWindowSize(oldwidth, Console.WindowHeight);
        }

        int DeleteResult(List<int> result)
        {
            Details();

            Console.SetCursorPosition(10, 9);
            Console.WriteLine("Valóban törölni akarod a rekordokat?");

            List<string> truefalse = new List<string>(new string[] { "Igen", "Nem" });
            int s = SelectOption(truefalse, false, 10, 11);

            if (s == 0)
                activedbase.activetable.DeleteRecords(result);

            return s;
        }

        private List<int> NumberFiltering(int field)
        {
            int cursortop = 12 + activedbase.activetable.TableFields.Count + 2;
            
            Console.SetCursorPosition(10, cursortop);
            Console.Write("Válaszd ki a használni kívánt relációt:");

            List<string> operators = new List<string>(new string[] { "<", ">", "=" });
            string op = operators[SelectOption(operators, false, 10, cursortop + 2)];

            string value = StringInput("A szűrési érték:", 10, cursortop + 6);

            List<int> ret = new List<int>();

            switch (op)
            {
                case "<": ret = LessThan(field, value); break;
                case ">": ret = GreaterThan(field, value); break;
                case "=": ret = Equals(field, value); break;
            }

            return ret;
        }

        private List<int> NonNumberFiltering(int field)
        {

            int cursortop = 12 + activedbase.activetable.TableFields.Count + 2;

            string value = StringInput("A szűrési érték:", 10, cursortop);

            List<int> ret = new List<int>();
            ret = Equals(field, value);

            return ret;
        }

        private List<int> LessThan(int field, string value)
        {
            List<int> ret = new List<int>();
            int i = 0;

            foreach (List<Data> record in activedbase.activetable.Records)
            {
                if (!activedbase.activetable.Records[i][field].IsNull)
                {
                    switch (activedbase.activetable.TableFields[field].Type)
                    {
                        case "Integer":
                            {
                                Integer dat = new Integer(Int32.Parse(record[field].GetValue()));
                                Integer val = new Integer(Int32.Parse(value));
                                if (dat < val) ret.Add(i);
                            } break;

                        case "Real":
                            {
                                Real dat = new Real(Double.Parse(record[field].GetValue()));
                                Real val = new Real(Double.Parse(value));
                                if (dat < val) ret.Add(i);
                            } break;
                    }
                }

                ++i;
            }

            return ret;
        }

        private List<int> GreaterThan(int field, string value)
        {
            List<int> ret = new List<int>();
            int i = 0;

            foreach (List<Data> record in activedbase.activetable.Records)
            {
                if (!activedbase.activetable.Records[i][field].IsNull)
                {
                    switch (activedbase.activetable.TableFields[field].Type)
                    {
                        case "Integer":
                            {
                                Integer dat = new Integer(Int32.Parse(record[field].GetValue()));
                                Integer val = new Integer(Int32.Parse(value));
                                if (dat > val) ret.Add(i);
                            } break;

                        case "Real":
                            {
                                Real dat = new Real(Double.Parse(record[field].GetValue()));
                                Real val = new Real(Double.Parse(value));
                                if (dat > val) ret.Add(i);
                            } break;
                    }
                }

                ++i;
            }

            return ret;
        }

        private List<int> Equals(int field, string value)
        {
            List<int> ret = new List<int>();
            int i = 0;

            foreach (List<Data> record in activedbase.activetable.Records)
            {
                if (!activedbase.activetable.Records[i][field].IsNull)
                {
                    switch (activedbase.activetable.TableFields[field].Type)
                    {
                        case "Integer":
                            {
                                Integer dat = new Integer(Int32.Parse(record[field].GetValue()));
                                Integer val = new Integer(Int32.Parse(value));
                                if (dat == val) ret.Add(i);
                            } break;

                        case "Real":
                            {
                                Real dat = new Real(Double.Parse(record[field].GetValue()));
                                Real val = new Real(Double.Parse(value));
                                if (dat == val) ret.Add(i);
                            } break;

                        case "Boolean":
                            {
                                Boolean dat = new Boolean(bool.Parse(record[field].GetValue()));
                                Boolean val = new Boolean(bool.Parse(value));
                                if (dat == val) ret.Add(i);
                            } break;

                        case "String":
                            {
                                if (record[field].GetValue() == value) ret.Add(i);
                            } break;
                    }
                }

                ++i;
            }

            return ret;
        }

        //TableOperations: option 5 - delete content of active table
        private void ClearTableContent()
        {
            Details();

            Console.SetCursorPosition(10, 9);
            Console.WriteLine("Valóban törölni akarod a tábla tartalmát?");

            List<string> truefalse = new List<string>(new string[] { "Igen", "Nem" });
            int s = SelectOption(truefalse, false, 10, 11);

            if (s == 0) activedbase.activetable.FlushContent();
        }

        //TableOperations: option 6 - delete active table from active database
        private void DeleteTable()
        {
            Details();

            Console.SetCursorPosition(10, 9);
            Console.WriteLine("Valóban törölni akarod a táblát?");

            List<string> truefalse = new List<string>(new string[] { "Igen", "Nem" });
            int s = SelectOption(truefalse, false, 10, 11);

            if (s == 0)
                activedbase.DeleteActiveTable();
        }
    }
}
